Skip to content

feat(core-ts): collection permalinks, step 2 — redirects, overlap checks, search - #73

Merged
Madraka merged 1 commit into
mainfrom
feat/collection-permalink-redirects
Oct 22, 2026
Merged

Madraka merged 1 commit into
mainfrom
feat/collection-permalink-redirects

Conversation

@Madraka

@Madraka Madraka commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

RFC-0038 / ADR-0040, step 2 of 3. Refs #50.

Redirects on change

  • SiteEngine.update → store/site-permalinks.ts. For each collection whose effective template changes, a RedirectPlan.move(oldPrefix, newPrefix, { match: "prefix", reason: "slug-change" }) is emitted into an OpBatch anchored on the site's new hash (OpBatch.anchorOn), in the same atomic batch as the site CAS (rule 4).
  • Locales: redirects are written for the default locale and each other site locale. Entries exist in every locale; taxonomy only writes the default one (see open questions).
  • Chains and loops: chains collapse (/posts → /blog → /journal sends /posts/x straight to /journal/x), and moving back to the default drops the self-redirect.
  • Conflicts: a stale rev throws ConflictError before planning. A failed op_guards assertion counts as a missed CAS, so nothing is written.

Overlap checks, both ways (permalink-paths.ts)

  • A changed template must not overlap: another collection's prefix (configured, or the default of a collection with entries), any taxonomy archive, a page at or under it, media, /search, or a locale prefix. The result is path_conflict / reserved_path, guarded on the CAS (noArchiveOverlapping, noPageWithin).
  • Reverse direction: pages and taxonomy archives can no longer be created or moved inside a configured prefix (checks plus site-row SQL guards). A default /<collection> prefix keeps today's rule, where a page wins.

Search

planSearch rewrites every entry row when a published snapshot's templates differ from the indexed one.

Tests (one package at a time)

  • core-ts 651/651: the new testing-permalinks.ts suite runs on sqlite, Miniflare D1 and Durable Object SQLite. It covers the moves, chains, back to default, overlaps, the reverse checks, stale and racing writers, and search hrefs.
  • astro-renderer 256/256: a new routing test serves /blog/hello-world and 301s /posts/hello-world?ref=x → /blog/hello-world?ref=x, on live and snapshot sources.
  • api 371/371.
  • taxonomy.ts shrank, so the size baseline is lowered.

Open questions (follow-ups, not blockers)

  1. Entry writes still check archives against the default /<collection>, and creating an entry in a new collection whose default prefix overlaps another collection's configured prefix is not refused. In that case entryAt prefers the configured one.
  2. Should updateTaxonomy write per-locale redirects too, so both behave the same?
  3. A move into a sub-prefix of itself (/posts → /posts/archive) is refused by RedirectPlan's loop check as invalid_redirect, not path_conflict.

🤖 Generated with Claude Code

…cks, search

RFC-0038 / ADR-0040, step 2:

- Changing a collection's template adds a prefix redirect (old → new) in
  the same atomic batch as the site CAS, for the default locale and each
  other site locale; RedirectPlan collapses chains and drops a redirect
  that would point at itself. `OpBatch.anchorOn` anchors the redirect
  writes on the site's new hash; a failed op guard is a missed CAS.
- A changed template must not overlap another collection's prefix, a
  taxonomy archive, a page at or under it, media, /search or a locale
  prefix (`path_conflict`, `reserved_path`), guarded on the CAS.
- Pages and taxonomy archives can no longer move into a configured
  collection prefix (checks and guards on the site row).
- Search rewrites every entry row when a published snapshot's templates
  differ from the indexed one.

Tests run on sqlite, D1 and Durable Object SQLite; the renderer serves
/blog/<slug> and redirects /posts/<slug>.

Refs #50

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Signed-off-by: Madraka <[email protected]>
@Madraka
Madraka merged commit 2bf0652 into main Oct 22, 2026
4 checks passed
@Madraka
Madraka deleted the feat/collection-permalink-redirects branch October 22, 2026 07:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant